/**
 * 串口通信类实现 - 树莓派专用版本
 * 
 * 实现了Linux下的串口通信功能
 */

#include "serial.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <iostream>

// 波特率映射表
static speed_t getBaudRate(int baudRate) {
    switch (baudRate) {
        case 9600: return B9600;
        case 19200: return B19200;
        case 38400: return B38400;
        case 57600: return B57600;
        case 115200: return B115200;
        case 230400: return B230400;
        case 460800: return B460800;
        case 921600: return B921600;
        default: return B115200;
    }
}

SerialPort::SerialPort() : fd_(-1), is_open_(false), baud_rate_(115200) {
    memset(&old_tio_, 0, sizeof(old_tio_));
}

SerialPort::~SerialPort() {
    close();
}

bool SerialPort::open(const std::string& portName, int baudRate, int dataBits, int stopBits, char parity) {
    close();  // 确保先关闭已打开的串口
    
    port_name_ = portName;
    baud_rate_ = baudRate;
    
    // 以非阻塞方式打开串口
    fd_ = ::open(portName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd_ == -1) {
        last_error_ = "无法打开串口: " + portName + " - " + strerror(errno);
        return false;
    }
    
    // 获取当前串口配置
    if (tcgetattr(fd_, &old_tio_) != 0) {
        last_error_ = "获取串口配置失败: " + std::string(strerror(errno));
        ::close(fd_);
        fd_ = -1;
        return false;
    }
    
    termios new_tio = old_tio_;
    
    // 设置波特率
    cfsetispeed(&new_tio, getBaudRate(baudRate));
    cfsetospeed(&new_tio, getBaudRate(baudRate));
    
    // 设置数据位
    new_tio.c_cflag &= ~CSIZE;
    switch (dataBits) {
        case 5: new_tio.c_cflag |= CS5; break;
        case 6: new_tio.c_cflag |= CS6; break;
        case 7: new_tio.c_cflag |= CS7; break;
        case 8: new_tio.c_cflag |= CS8; break;
        default: new_tio.c_cflag |= CS8; break;
    }
    
    // 设置校验位
    new_tio.c_cflag &= ~(PARENB | PARODD);
    if (parity == 'E') {
        new_tio.c_cflag |= PARENB;
    } else if (parity == 'O') {
        new_tio.c_cflag |= PARENB | PARODD;
    }
    
    // 设置停止位
    new_tio.c_cflag &= ~CSTOPB;
    if (stopBits == 2) {
        new_tio.c_cflag |= CSTOPB;
    }
    
    // 其他设置
    new_tio.c_cflag |= (CLOCAL | CREAD);  // 本地连接，启用接收
    new_tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  // 原始模式
    new_tio.c_oflag &= ~OPOST;  // 原始输出
    new_tio.c_iflag &= ~(INPCK | ISTRIP | IXON | IXOFF | IGNBRK);
    
    // 设置超时参数
    new_tio.c_cc[VTIME] = 0;  // 超时时间（0.1秒为单位）
    new_tio.c_cc[VMIN] = 0;   // 最小接收字符数
    
    // 清空缓冲区
    tcflush(fd_, TCIFLUSH);
    
    // 应用配置
    if (tcsetattr(fd_, TCSANOW, &new_tio) != 0) {
        last_error_ = "设置串口配置失败: " + std::string(strerror(errno));
        ::close(fd_);
        fd_ = -1;
        return false;
    }
    
    is_open_ = true;
    last_error_.clear();
    return true;
}

void SerialPort::close() {
    if (is_open_ && fd_ != -1) {
        tcsetattr(fd_, TCSANOW, &old_tio_);  // 恢复原始配置
        ::close(fd_);
        fd_ = -1;
        is_open_ = false;
    }
}

bool SerialPort::isOpened() const {
    return is_open_;
}

int SerialPort::write(const std::vector<uint8_t>& data) {
    if (!is_open_ || fd_ == -1) {
        last_error_ = "串口未打开";
        return -1;
    }
    
    ssize_t bytes_written = ::write(fd_, data.data(), data.size());
    if (bytes_written < 0) {
        last_error_ = "发送数据失败: " + std::string(strerror(errno));
    }
    
    return static_cast<int>(bytes_written);
}

int SerialPort::write(const std::string& data) {
    std::vector<uint8_t> buffer(data.begin(), data.end());
    return write(buffer);
}

int SerialPort::read(std::vector<uint8_t>& buffer, size_t size) {
    if (!is_open_ || fd_ == -1) {
        last_error_ = "串口未打开";
        return -1;
    }
    
    buffer.resize(size);
    ssize_t bytes_read = ::read(fd_, buffer.data(), size);
    
    if (bytes_read < 0) {
        last_error_ = "接收数据失败: " + std::string(strerror(errno));
        return -1;
    }
    
    buffer.resize(bytes_read);
    return static_cast<int>(bytes_read);
}

std::string SerialPort::readString(size_t size) {
    std::vector<uint8_t> buffer;
    int bytes_read = read(buffer, size);
    
    if (bytes_read <= 0) {
        return "";
    }
    
    return std::string(buffer.begin(), buffer.end());
}

std::string SerialPort::readLine() {
    if (!is_open_ || fd_ == -1) {
        last_error_ = "串口未打开";
        return "";
    }
    
    std::string line;
    char c;
    
    while (true) {
        ssize_t bytes_read = ::read(fd_, &c, 1);
        
        if (bytes_read <= 0) {
            if (errno != EAGAIN) {
                last_error_ = "读取数据失败: " + std::string(strerror(errno));
            }
            break;
        }
        
        if (c == '\n') {
            break;
        }
        
        if (c != '\r') {
            line += c;
        }
    }
    
    return line;
}

void SerialPort::setReadTimeout(int timeoutMs) {
    if (!is_open_ || fd_ == -1) {
        return;
    }
    
    termios new_tio;
    if (tcgetattr(fd_, &new_tio) == 0) {
        new_tio.c_cc[VTIME] = timeoutMs / 100;  // 转换为0.1秒为单位
        tcsetattr(fd_, TCSANOW, &new_tio);
    }
}

std::vector<std::string> SerialPort::getAvailablePorts() {
    std::vector<std::string> ports;
    
    // 树莓派常见的串口设备
    const char* common_ports[] = {
        "/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2",
        "/dev/ttyACM0", "/dev/ttyACM1", "/dev/ttyACM2",
        "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2",
        "/dev/ttyAMA0", "/dev/ttyAMA1", "/dev/ttyAMA2"
    };
    
    for (const char* port : common_ports) {
        if (access(port, F_OK) == 0) {
            ports.push_back(port);
        }
    }
    
    return ports;
}

std::string SerialPort::getLastError() const {
    return last_error_;
}